home *** CD-ROM | disk | FTP | other *** search
- .nr PS 10
- .nr VS 12
- .nr PD .7v
- .nr LL 6.5i
- .TL
- A Portable Exception Handling Mechanism for C++
- .AU
- Mary Fontana
- LaMott Oren
- .AI
- Texas Instruments Incorporated
- Computer Science Center
- Dallas, TX 75265
- fontana@csc.ti.com
- oren@csc.ti.com
- .AU
- Martin Neath
- .AI
- Texas Instruments Incorporated
- Information Technology Group
- Austin, TX 78714
- neath@itg.ti.com
- .AB
- The Texas Instruments C++ Object-Oriented Library (COOL) is a collection of
- classes, templates, and macros for use by C++ programmers who need to write
- complex yet portable applications. The COOL exception handling mechanism is
- one component of this library that substantially improves the development and
- expressive capabilities available to programmers by allowing them to control
- the action to be taken by their programs when exceptional or unexpected
- situations occur. This paper describes the facilities provided by COOL to
- raise, handle, and proceed from exceptions in a C++ class library or program
- and provides several examples of its use and flexibility.
- .AE
- .NH 1
- Introduction
- .LP
- The Texas Instruments C++ Object-Oriented Library (COOL) is a collection of
- classes, templates, and macros for use by C++ programmers writing complex
- applications. An important feature of this library is the ability to create
- and raise exceptions in the library for which a user of this class library can
- define his/her own exception handler routines to effectively and appropriately
- handle the exceptions in an application at runtime. This is especially
- important since current C++ compiler implementations do not contain an
- exception handling facility [6]. For an overview of the COOL class library, see
- the paper,
- .I
- COOL - A C++ Object-Oriented Library
- .R
- [2].
- For complete details, see the reference document,
- .I
- COOL User's Guide
- .R
- [8].
-
- The COOL exception handling facility consists of a set of classes and macros to
- define, create, raise and handle exceptions. It is implemented with the COOL
- macro facility [3] and symbolic computing capability [4] and is similar to the
- Common Lisp Condition Handling system [1] in that both implement an exception
- system with the ability for resumption. Briefly, when a program encounters a
- particular or unusual situation that is often (but not necessarily) an error,
- it can (1) represent the situation in an exception object, (2) announce that
- the situation has occurred by raising the exception, (3) provide ways to deal
- with the situation by defining and establishing handlers, and (4) continue or
- proceed from the situation after invoking a handler. One possible action for a
- handler is to correct some piece of erroneous information and retry the
- operation.
-
- The COOL exception handling facility represents exceptions as objects derived
- from an exception class and provides a generic exception handler class, a set
- of predefined subclasses of the base exception class, and a set of default
- exception handler functions. Several macros -- \fBEXCEPTION\fR, \fBRAISE\fR,
- \fBSTOP\fR, and \fBVERIFY\fR -- provide a simple interface to the exception
- handling facility and allow a programmer to easily create and raise exceptions.
- In addition, the macro \fBIGNORE_ERRORS\fR provides a convenient means by which
- a programmer can explicitly disable the exception handling system while
- executing a block of statements. Finally, the \fBDO_WITH_HANDLER\fR and
- \fBHANDLER_CASE\fR macros offer functionality similar to that described by
- Koenig and Stroustrup [5] to associate a block of statements with a provision
- for handling a specific set of possible exceptions.
-
- Exception handlers are also represented as objects derived from an exception
- handler class. When an exception handler object is instantiated, it is placed
- at the top of a global exception handler stack. When an exception handler
- object is destroyed, the handler is removed from the exception handler stack.
- This stack is maintained in a similar way to that described by Miller [7]. When
- an exception is raised, a search is performed for an appropriate handler
- starting at the top of the exception handler stack. Since the most recently
- defined handler objects are placed at the top of the stack, localized or
- specialized handlers take precedence over more generic system-wide handlers.
- When a match against an exception type or group name is found, the exception
- handler object invokes the handler function. An exception handler function
- might report the exception to the standard error stream and terminate the
- program, generate debug information by dumping a core image or stack trace to
- disk, or attempt to fix the problem and retry the operation again.
- .NH 1
- The Exception Class
- .LP
- Exceptions are represented as objects of an exception class and are used as a
- means of saving and communicating the state information representing a
- particular problem or condition to the appropriate exception handler. When an
- exception can be corrected and resumption is possible, information on the new
- state is stored in the exception object by the invoked exception handler
- function and returned to the point at which the exception was raised. The COOL
- \fBException\fR class is the base class from which specialized exception
- classes are derived. It contains data members to store a message string prefix,
- a format control string, a list of one or more group names or exception aliases
- for which this exception class is appropriate, and a flag to indicate whether
- or not an exception is handled. User-derived exception classes can include
- additional data members for saving the incorrect values detected by a program.
- These values report the state to the exception handler and are often used by an
- exception handler when reporting the exception/error message to some
- interactive stream.
-
- The \fBException\fR class has several generic member functions for use by all
- exception objects. The virtual member function \fBreport()\fR uses the message
- prefix and format string data members to report an exception message on a
- specified stream. The virtual member function \fBraise()\fR searches for an
- exception handler and invokes it if found. The \fBmatch()\fR member function
- indicates if an exception object is included in one of the exception group
- names (aliases). The output operator is overloaded for the \fBException\fR
- class to call the \fBreport()\fR member function. Member functions to query
- whether or not an exception has been handled and to set the handled flag are
- also available. Finally, the virtual \fBdefault_handler()\fR member function is
- invoked if no exception handler is found.
-
- As mentioned above, data members can be included in a derived exception class
- as a way for the signaller (the one who raises the exception) to indicate to an
- exception handler ways of proceeding from the exception. For example, if an
- exception occurs because a variable has an incorrect value, an exception object
- of the appropriate type is created and then the exception is raised. The
- exception object defined for this situation would have a data member with the
- incorrect value and a data member for the new value. An exception handler
- could be established to handle this type of situation by supplying a new value
- (possibly by interactively informing the user about the incorrect value and
- querying for a new value through an appropriate interface), store this new
- value in the exception object, and return the exception object to the
- signaller. The signaller would then assign this new value to the variable in
- error and execution at the point the exception was raised would resume.
- .NH 1
- Exception Handler Class
- .LP
- When an exception handler is invoked after a successful search of the global
- exception handler stack, it's handler function is called with the raised
- exception object as an argument. The handler function may correct the problem,
- ignore it, or do most anything else appropriate. For the case in which an
- attempt is made to fix the problem and resumption is possible, the point in the
- program or library at which the exception is raised can contain statements to
- determine the new or changed values and state information, update any local
- variables accordingly, and resume execution. All the information and processing
- associated with exception handling is represented by an instance of an
- exception handler class.
-
- The \fBExcp_Handler\fR class has two data members. The first is a list of one
- or more exception types or group names (aliases) and the second is a pointer to
- a function to be called to handle a raised exception that matches against a
- value in the exception type list. These data members are initialized by the
- argument list of the constructor and cannot be changed once set. The
- \fBExcp_Handler\fR class has a single virtual member function
- \fBinvoke_handler()\fR that takes a single argument -- a pointer to the
- exception object -- and invokes the exception handler function. This function
- may or may not return, depending upon whether the handler attempts to resume
- execution or terminate the operation.
- .NH 1
- Exception Group Names (Aliases)
- .LP
- As with most exception handling systems, the COOL exception facility supports
- the grouping of exceptions by the class hierarchy. However, as mentioned
- above, the COOL exception handling facility also supports the concept of
- exception group names or aliases. Grouping of exception names is implemented
- through the alias/group name data member in each exception object. These group
- names allow a programmer to raise a single exception but associate that
- exception with several names or aliases rather than with just one. This means
- that a single exception class might be handled by one of several different
- exception handlers appropriate under different situations. The net result for
- the programmer is that only one exception class needs to be defined instead of
- several very similar classes. The group names are implemented using the COOL
- symbolic computing facility [4] for efficiency, but could be implemented using
- simple character strings to represent each name.
-
- For example, suppose a programmer is implementing a parameterized Vector<Type>
- class in a generic class library to be used by several other programmers in the
- company. Some of these other programmers want to have a detailed set of options
- for dealing with exceptions, including resumption, while others want only a
- simple fail-safe termination mechanism. The Vector class programmer wishes to
- provide exception handling in the overloaded Vector<Type>::operator[] member
- function that satisfies all potential users of the class. To accomplish this, a
- single exception class \fBOut_Of_Bounds\fR is derived from the base class
- \fBException\fR with appropriate data members added to contain the old index
- value and a possible new value. If an index out of bounds error is detected, an
- exception object is created with one type name provided by the class hierarchy
- mechanism -- \fBOut_Of_Bounds\fR -- and two group names -- \fBVector_Error\fR
- and \fBFatal_If_Not_Handled\fR -- representing different exception reporting
- granularity. These three names for one exception type allow three different
- users of this class to achieve varying levels of sophistication in their
- exception handlers while requiring the class programmer to only implement one
- exception class for the parameterized vector class. If an Out_Of_Bounds
- exception is raised, the first exception handler found on the global exception
- handler stack that can handle either the exception type or one of the three
- exception group names supported will be invoked.
- .NH 1
- Predefined Exception Types and Handlers
- .LP
- COOL provides seven predefined exception class and five default exception
- handlers. The \fBException\fR class is the base exception class from which all
- other exception classes are derived. The \fBWarning\fR, \fBFatal\fR,
- \fBError\fR, and \fBSystem_Signal\fR classes are immediately derived from the
- base class. The \fBSystem_Error\fR and \fBVerify_Error\fR classes are derived
- from the \fBError\fR class. Each of these predefined exception types has a
- default report member function and a default exception handler member function
- that is only invoked if no other exception handler is
- established by the programmer and found on the global exception handler stack
- when an exception is raised.
-
- For exceptions of type \fBError\fR and \fBFatal\fR, the default exception
- handler reports the error message on the standard error stream and terminates
- the program with \fBexit()\fR or writes a core image and/or stack trace out to
- disk with \fBabort()\fR. If the exception is of type \fBWarning\fR, the warning
- message is reported on the standard error stream and the program resumes at the
- point at which the exception was raised. If the exception is of type
- \fBSystem_Error\fR, the system error message is reported on the standard error
- stream and the program is terminated. If the exception is of type
- \fBSystem_Signal\fR, the signal is reported and the program resumes execution
- after the call of the system function \fBsignal(2)\fR. In all cases, the default
- exception handler is merely a place-holder to insure that there is at least one
- handler for each type of exception available at all times on the global
- exception handler stack. Users are expected to provide their own
- exception handler classes that handle particular exception group names used
- within the COOL class library in a more appropriate application-specific manner.
- .NH 1
- Exception Handling Macros
- .LP
- The COOL exception handling facility uses the COOL macro facility [3] to create
- macros for creating, raising, and manipulating exceptions. The \fBEXCEPTION\fR
- macro simplifies the process of creating an instance of a particular type of
- exception object. The \fBRAISE\fR macro allows the programmer to easily
- construct and raise an exception, then perform a search for an appropriate
- exception handler and invoke the handler function. The \fBSTOP\fR macro is
- similar to \fBRAISE\fR, except that it guarantees to end the program if the
- exception is not handled. The \fBVERIFY\fR macro raises an exception if an
- assertion for some specified expression evaluates to zero. The
- \fBIGNORE_ERRORS\fR macro is a wrapper that can be placed around a body of
- statements to ignore exceptions raised while executing that body. The
- \fBDO_WITH_HANDLER\fR macro establish an exception handler effective for the
- duration of a block. Finally, the \fBHANDLER_CASE\fR macro establishes an
- exception handler that transfers control to a series of exception-case clauses
- similar to the \fBtry\fR/\fBcatch\fR concept proposed by Koenig/Stroustrup [5].
- .NH 2
- The EXCEPTION Macro
- .LP
- The \fBEXCEPTION\fR macro simplifies the process of creating an instance of a
- particular type of exception object. It provides an interface for the
- application programmer to create an exception object using the specified
- arguments to indicate one or more group names, initialize any data members, or
- generate a format message. \fBEXCEPTION\fR is implemented as a COOL macro and
- has the following syntax:
- .DS I
- \fBEXCEPTION (\fIexcp_name\fB [, \fIgroup_names\fR] [, \fIformat_string\fR] [, \fIargs\fB])\fR
- .DE
- where \fIexcp_name\fR is the COOL symbol representing the exception class type
- (such as, \fBError\fR or \fBWarning\fR), \fIgroup_names\fR are one or more
- pointers to COOL symbols each of which represents a group or alias name for
- this exception, \fIformat_string\fR is a \fBprintf(2)\fR compatible control
- string, and \fIargs\fR are any combination of format arguments and keyword
- arguments to initialize data members. For example, the following macro
- invocation might be used to implement the index-bounds exception for the
- Vector<Type> class discussed above:
- .DS I
- EXCEPTION (Out_Of_Bounds, SYM(Vector_Error), SYM(Fatal_If_Not_Handled)),
- "Index %d out of bounds for vector of type %s", bad_index = i, #Type);
- .DE
- The first argument is the exception type (ie. a new exception class derived
- from \fBException\fR), the second and third arguments are entries in the COOL
- symbol table for two group names (aliases) to be associated with this exception
- object, the third argument is a message string, and the last two arguments
- provide values for the fields in the message.
- The fourth argument also initializes a data member. When expanded, this macro
- generates:
- .DS I
- (Exception_g = new Out_Of_Bounds(),
- Exception_g = set_group_names(2, SYM(Vector_Error), SYM(Fatal_If_Not_Handled)),
- Exception_g->format_msg = ERR_MSG (hprintf ("Index %d out of bounds for vector of type %s",
- i, #Type)),
- ((Out_Of_Bounds*)Exception_g)->bad_index = i,
- Exception_g);
- .DE
- This comma-separated expression creates a new \fBOut_Of_Bounds\fR exception
- object on the heap and assigns it to the pointer \fBException_g\fR. The two
- group names are added as symbols using the \fBset_group_names()\fR member
- function. The format message is created by \fBhprintf()\fR, which is a
- variation of \fBprintf(2)\fR that returns a formated string allocated on the
- heap. This string is placed in the COOL \fBERR_MSG\fR table that facilitates
- simple internationalization of text strings in an application [4].
- Finally, the data member \fBbad_index\fR is initializied with the value \fBi\fR.
- .NH 2
- The RAISE Macro
- .LP
- The \fBRAISE\fR macro simplifies the process of creating and raising an
- exception. The exception object is constructed using \fBEXCEPTION\fR and is
- raised using the member function \fBraise()\fR. If one is found of the
- appropriate type, it's handler function is invoked and passed the exception
- object as an argument. \fBRAISE\fR returns the exception object if the
- exception handler function returns or if no exception handler is found.
- \fBRAISE\fR is implemented as a COOL macro and has the following syntax:
- .DS I
- \fBRAISE (\fIexcp_name\fB [, \fIgroup_names\fR] [, \fIformat_string\fR] [, \fIargs\fB])\fR
- .DE
- where \fIexcp_name\fR is the COOL symbol representing the exception class type
- (such as, \fBError\fR or \fBWarning\fR), \fIgroup_names\fR are one or more
- pointers to COOL symbols each of which represents a group or alias name for
- this exception, \fIformat_string\fR is a \fBprintf(2)\fR compatible control
- string, and \fIargs\fR are any combination of format arguments and keyword
- arguments to initialize data members.
-
- The \fBRAISE\fR macro is used extensively in COOL and is often the most
- convenient form used by programmers. The following example continues with the
- index-bounds exception for the Vector<Type> class from above. Suppose an
- application programmer is working on a tutorial programming environment that
- provides assistance at runtime to novice programmers. The programmer wishes to
- set up an exception handler to handle the index-bounds error by prompting for a
- new value, storing the result in the exception object, and retrying the
- operation. The class programmer implementing the Vector<Type> could write
- the code for the member function Vector<Type>::operator[] in the class library
- and raise an exception and process it as follows:
- .DS I
- class Out_Of_Bounds : public Error {
- public:
- unsigned int bad_index;
- unsigned int new_index;
- char* container;
- char* type;
- Out_of_Bounds() { format_msg = "Index %d out of bounds for %s of type %s"; }
- virtual void report (ostream& os) { os << msg_prefix << form(format_msg, bad_index, container, type);}
- };
-
- int Vector<Type>::operator[] (int i) {
- while(TRUE) {
- if (i >= 0 && i < this->number_elements)
- return this->data[i];
- else {
- Error* e = RAISE (Out_of_Bounds, bad_index = i, container = "Vector", type = #Type);
- if (e->exception_handled())
- i = e->new_index;
- }
- }
- }
- .DE
- The application programmer writing the programming environment defines an
- exception handler function to prompt for a new index and an instance of a
- handler object to associate with the function for the \fBOut_Of_Bounds\fR
- exception in the following manner:
- .DS I
- void Bounds_Index_Handler (Exception& excp) {
- excp.report(cout);
- cout << "New index to use instead: " << flush;
- cin >> excp.new_index;
- excp.handled(TRUE);
- }
-
- Excp_Handler vec_eh (Bounds_Index_Handler, SYM(Out_Of_Bounds));
- .DE
- The exception handler object \fBvec_eh\fR should be declared at what ever
- scope is necessary for exceptions of this type to be handled in this manner.
- This is usually, but not always, declared as a global instance so as to insure
- that the handler is available at all times during the run of an application.
- When the user of this system runs the program with an erroneous index, the
- \fBOut_Of_Bounds\fR exception is raised in the class library, the exception
- handler \fBBounds_Index_Handler\fR written by the application programmer is
- invoked and prompts for a new index, then the operation retryed. Note that the
- three programmer's involved in this system (the class programmer, the
- application programmer, and the novice programmer) had no interaction with each
- other and no discussion over the design and interface to the exception handling
- facility. However, the class programmer was able to use a flexible exception
- handling system that was customized with an application-specific handler to
- afford a more helpful system for the novice programmer. Finally, note that in
- this example, proceeding from the raised exception involves no use of the
- system setjmp/longjmp functions.
- .NH 2
- The STOP Macro
- .LP
- The \fBSTOP\fR macro creates and raises an exception similar to the \fBRAISE\fR
- macro except that it guarantees to terminate program execution if an exception
- handler returns (ie. attempts to resume) or if no exception handler is found.
- The exception object is constructed in the same manner using the
- \fBEXCEPTION\fR macro and raised using the member function \fBstop()\fR.
- \fBSTOP\fR is implemented as a COOL macro and has the following syntax:
- .DS I
- \fBSTOP (\fIexcp_name\fB [, \fIgroup_names\fR] [, \fIformat_string\fR] [, \fIargs\fB])\fR
- .DE
- where \fIexcp_name\fR is the COOL symbol representing the exception class type
- (such as, \fBError\fR or \fBWarning\fR), \fIgroup_names\fR are one or more
- pointers to COOL symbols each of which represents a group or alias name for
- this exception, \fIformat_string\fR is a \fBprintf(2)\fR compatible control
- string, and \fIargs\fR are any combination of format arguments and keyword
- arguments to initialize data members.
- .NH 2
- The VERIFY Macro
- .LP
- The \fBVERIFY\fR macro asserts that an expression has a non-zero value by
- raising an exception of the specified type if the expression evaluates to zero.
- The exception object is constructed with \fBEXCEPTION\fR and is raised using
- the member function \fBraise()\fR. The exception type is optional and,
- if not given, defaults to \fBVerify_Error\fR. This exception class is derived
- from \fBError\fR and contains a data member for storing a string representation
- of the expression that failed. \fBVERIFY\fR is implemented as a COOL macro and
- has the following syntax:
- .DS I
- \fBVERIFY (\fItest_expression\fB, \fIexcp_name\fB = Verify_Error\fR [, \fIgroup_names\fR] [, \fIformat_string\fR] [, \fIargs\fB])\fR
- .DE
- where \fItest_expression\fR is the C++ expression to be verified,
- \fIexcp_name\fR is the optional argument specifying the exception type,
- \fIgroup_names\fR are one or more pointers to COOL symbols each of which
- represents a group or alias name for this exception, \fIformat_string\fR is a
- \fBprintf(2)\fR compatible control string, and \fIargs\fR are any combination
- of format arguments and keyword arguments to initialize data members.
- For example, the
- following macro invocation might be used to implement an alternate approach
- for the index-bounds exception discussed above:
- .DS I
- int Vector<Type>::operator[] (int i) {
- VERIFY ((i >= 0 && i < this->number_elements));
- return this->data[i];
- }
- .DE
- Since only the expression to assert is passed as an argument, the \fBVERIFY\fR
- macro creates a \fBVerify_Error\fR exception object by default and initializes
- the inherited data members. When expanded, this macro generates:
- .DS I
- if (!(i >= 0 && i < this->number_elements))
- (Exception_g = new Verify_Error(),
- Exception_g)->raise();
- .DE
- .NH 2
- The IGNORE_ERRORS Macro
- .LP
- The \fBIGNORE_ERRORS\fR macro ignores an exception that is raised while
- executing a body of statements. If an exception of a specified type or types is
- raised while within the scope of this body, the macro insures that the handler
- for that exception is not invoked, but rather, control is returned to the point
- immediately following the body. \fBIGNORE_ERRORS\fR is implemented as a COOL
- macro and has the following syntax:
- .DS I
- \fBIGNORE_ERRORS (\fIexcp_ptr\fR [, \fIexcp_class\fB = Error\fR] [, \fIgroup_names\fR]) { \fIbody\fB }\fR
- .DE
- If an exception of type \fIexcp_class\fR (or with group \fIgroup_names\fR) is
- raised while executing \fIbody\fR, then \fIexcp_ptr\fR is set to the address of
- this exception object and program control transfers to the statement following
- \fBIGNORE_ERRORS\fR. If no exception is raised while executing \fIbody\fR,
- then \fIexcp_ptr\fR is set to \fBNULL\fR. The exception must have been raised
- with the \fBRAISE\fR, \fBSTOP\fR, or \fBVERIFY\fR macros.
- If \fIexcp_class\fR is not specified, the
- default exception class is \fBError\fR. \fBIGNORE_ERRORS\fR is implemented
- using the system functions, setjmp and longjmp. As a result, the statements
- within the braces should not require destructors to be invoked because the
- setjmp/longjmp mechanism does not currently support this capability.
-
- In the following program fragment, \fBIGNORE_ERRORS\fR is used to ignore an
- exception of type \fBError\fR raised while using operator[] of the Vector<Type>
- class. In this case, the exception object is send to the standard error
- stream and execution continues. If \fBIGNORE_ERRORS\fR were not used
- and no other exception handler had been defined, the default exception handler
- for \fBError\fR would terminate the program with a call to \fBexit(2)\fR.
- .DS I
- Vector<int> data[4];
- Error* e;
- IGNORE_ERRORS (e) {
- int i;
- i = data[5];
- }
- if (e != NULL)
- cerr << e;
- .DE
- .NH2
- The DO_WITH_HANDLER Macro
- .LP
- The \fBDO_WITH_HANDLER\fR macro establishes an exception handler whose scope is
- restricted to a specified body of statements. An exception handler that
- matches against one of the exception types or group names in the exception list
- is established during execution of a series of statements. The specified
- exception handler will be invoked if an exception of the specified type or
- group is raised and no other more-recently-established handler matches the type
- or group names. The exception must have been raised with the \fBRAISE\fR,
- \fBSTOP\fR, or \fBVERIFY\fR macros.
- \fBDO_WITH_HANDLER\fR is implemented as a COOL macro and has
- the following syntax:
- .DS I
- \fBDO_WITH_HANDLER (\fIexh_func\fR [, \fIexcp_types\fR]) { \fIbody\fB }\fR
- .DE
- where \fIexh_func\fR is the name of an exception handler function,
- \fIexcp_types\fR is a list of one or more exception types and group names, and
- \fIbody\fR specifies one or more C++ statements surrounded by braces. In the
- following example, a specialized exception handler for the index-bounds problem
- in the Vector<Type>::operator[] class is established for a small body of code:
- .DS I
- extern void New_Out_Of_Bounds_Handler(Exception&);
- Vector<int> data[4];
- DO_WITH_HANDLER (New_Out_Of_Bounds_Handler, SYM(Out_Of_Bounds)) {
- int sum;
- for(int i = 0; i <= data.length(); i++)
- sum += data[i];
- }
- .DE
- This code fragment contains a typical indexing problem where the programmer
- has an inaccurate loop-termination test, thus incrementing the index one too
- many times and causing an exception to be raised. When expanded, this macro
- generates:
- .DS I
- extern void New_Out_Of_Bounds_Handler(Exception&);
- Vector<int> data[4];
- {
- Excp_Handler _do_eh(New_Out_Of_Bounds_Handler, SYM(Out_Of_Bounds));
- int sum;
- for(int i = 0; i <= data.length(); i++)
- sum += data[i];
- }
- .DE
- .NH2
- The HANDLER_CASE Macro
- .LP
- The \fBHANDLER_CASE\fR macro establishes an exception handler that transfers
- control to a set of exception-case clauses when an exception is raised while
- executing a body of statements. \fBHANDLER_CASE\fR is implemented as a COOL
- macro and has the following syntax:
- .DS I
- \fBHANDLER_CASE { \fIbody\fB }\fR { \fIcase_clauses\fR }
- \fIcase_clauses\fR ::= \fBcase\fR ([\fIexcp_spec\fR]) \fB:\fR {\fIstatements\fR} [\fIcase_clauses\fR]
- \fIexcp_spec\fR ::= [\fIexcp_types\fR] [,\fI excp_class excp_decl\fR]
- \fIexcp_types\fR ::= \fIexcp_class_or_group_type\fR [, \fIexcp_types\fR]
- .DE
- If an exception is raised while executing \fIbody\fR, an exception handler will
- be invoked to transfer control to \fIcase_clauses\fR. The statements of the
- \fIcase_clause\fR whose \fIexcp_spec\fR matches the raised exception type or
- one of its group names is executed. The variable \fIexcp_decl\fR is bound to
- the \fIexcp_class\fR exception object raised and may be referenced by any
- statement in the matching \fIcase_clause\fR. The exception must have been
- raised with \fBRAISE\fR, \fBSTOP\fR, or \fBVERIFY\fR.
- Finally, as in \fBIGNORE_ERRORS\fR, the
- \fBHANDLER_CASE\fR macro is implemented using the system functions, setjmp and
- longjmp. As a result, the statements within the matching \fIcase_clause\fR
- should not require destructors to be invoked because the setjmp/longjmp
- mechanism does not currently support this capability. The following example
- shows the use of this macro with the index-bounds problem used throughout this
- paper:
- .DS I
- Boolean calculate_sum (Vector<int>& v1, int start, int end)
- {
- HANDLER_CASE {
- int sum;
- for(int i = start; i <= end; i++)
- sum += v1[i];
- }
- v1.push(sum);
- }
- case (SYM (Out_Of_Bounds), Error eh) : {
- cerr << eh;
- return FALSE;
- }
- case (SYM (Resize_Error), SYM (Static_Error), Error eh) : {
- cerr << eh;
- abort();
- }
- case (Error eh) : {
- cerr << eh;
- exit();
- }
- return TRUE;
- }
- .DE
- This function takes a reference to a vector object, a starting index, and an
- ending index to compute the sum of the elements between and including these
- indexes. If an exception occurs during this operation, control is transferred
- to the appropriate case statement clause. If an exception of type
- \fBOut_Of_Bounds\fR is raised, the exception object is printed on the standard
- error stream and the value FALSE is returned from the function. If the raised
- exception has a group name of either \fBResize_Error\fR or \fBStatic_Error\fR,
- the exception object is printed on the standard error stream and the program
- aborts. Finally, as a default condition, if any other type of exception is
- raised, the exception object is printed on the standard error stream and the
- program exits. If no exceptions are raised, the sum of the elements is pushed
- onto the end of the vector object and the value TRUE is returned from the
- function.
- .NH 1
- COOL Exception Handling Comparison to Koenig/Stroustrup Proposal
- .LP
- The COOL exception handling facility implements a portable, compiler
- independent, object-oriented exception handling capability. Exceptions are
- classified according to subtype relationships making it easy to test for a
- group of exceptions. These exception objects have data members through which
- state information is conveyed from the point at which the exception is raised
- to the handler. The base exception and handler classes contain generic virtual
- functions upon which more sophisticated capabilities can be built through
- inheritance and derivation.
-
- The COOL exception handling macros, \fBRAISE\fR and \fBHANDLER_CASE\fR, provide
- the same type of functionality as the \fBthrow\fR and \fBtry-catch\fR
- statements proposed by Koenig and Stroustrup in their paper,
- .I
- Exception Handling for C++
- .R
- [5]. Both \fBthrow\fR and \fBRAISE\fR transfer control to the most recently
- establish handler for a particular type of exception. However, any object may
- be used as an argument in a \fBthrow\fR expression, whereas \fBRAISE\fR only
- passes exception objects. In a similar manner, the \fBtry-catch\fR block and
- the \fBHANDLER_CASE\fR macro establish some handlers while executing a body of
- statements. The difference here is that the \fBcatch\fR expression in a
- \fBtry\fR block is like a function definition and any data type can be
- specified in the exception declaration. The case statements in the
- \fBHANDLER_CASE\fR macro, on the other hand, accept only COOL symbol objects.
- These symbols allow for group names and aliases to be used to handle a single
- kind of exception in one of several ways.
-
- These differences are minor, however, when compared to the philosophical models
- each system follows: termination versus resumption. In the one, the \fBthrow\fR
- unwinds the stack before the call of the exception handler, thus supporting a
- termination model for exception handling, while in the second, the \fBRAISE\fR
- macro expands into a function call before the stack is unwound, thus supporting
- a resumption model for exception handling.
- .NH 1
- Conclusion
- .LP
- The COOL exception handling facility is a set of classes and macros that
- provide a mechanism to detect and raise an exception and independently
- establish and invoke an exception handler to deal with the exception in another
- part of the application. An exception handler may either fix the problem and
- resume execution, retry the operation, or terminate the program. The virtual
- member functions \fBreport\fR, \fBraise\fR, \fBdefault_handler\fR, and
- \fBmatch\fR can be customized in user-defined exception classes derived from
- the base \fBException\fR and \fBExcp_Handler\fR classes. The macros
- \fBEXCEPTION\fR, \fBRAISE\fR, \fBSTOP\fR, \fBVERIFY\fR, \fBIGNORE_ERRORS\fR,
- \fBDO_WITH_HANDLER\fR, and \fBHANDLER_CASE\fR provide a consistent and
- convenient way for the programmer to create, raise, and handle exceptions.
-
- There are still a number of problems that need to be addressed in the COOL
- exception handling system. Of particular concern are how to handle exceptions
- raised in constructors and destructors, and the destruction of objects when
- setjmp/longjmp are used. Texas Instruments has been using the exception
- handling facility internally on several projects in conjunction with the COOL
- class library. We have found that the use of a flexible exception handling
- system enables programmer's to customize the error handling to suit a specific
- application. As a result, class libraries are more useful and reusable, thus
- significantly increasing the productivity of the programmer and thus enabling
- applications to be prototyped in a shorter time period than might otherwise be
- possible. COOL is currently up and running on a Sun SPARCstation 1 (TM)
- running SunOS (TM) 4.x,
- .FS
- SunOS and SPARCstation 1 are trademarks of Sun Microsystems, Inc.
- .FE
- a PS/2 (TM)
- .FS
- PS/2 is a trademark of International Business Machines Corporation.
- .FE
- model 70 running SCO XENIX\(rg
- .FS
- XENIX is a registered trademark of Microsoft Corporation.
- .FE
- 2.3, a PS/2 model 70 running OS/2 1.1, and
- a MIPS running RISC/os 4.0. The SPARC and MIPS ports utilize the AT&T C++
- translator (cfront) version 2.0 and the XENIX and OS/2 ports utilize the
- Glockenspiel translator with the Microsoft C compiler.
- .NH 1
- References
- .IP [1]
- Andy Daniels and Kent Pitman,
- .I
- Common Lisp Condition System Revision #18,
- .R
- ANSI X3J13 subcommittee on Error Handling, March 1988.
- .IP [2]
- Mary Fontana, Martin Neath and Lamott Oren,
- .I
- COOL - A C++ Object-Oriented Library,
- .R
- Information Technology Group, Austin, TX, Internal Original Issue January 1990.
- .IP [3]
- Mary Fontana, Martin Neath and Lamott Oren,
- .I
- A Portable Implementation of Parameterized Templates Using A Sophisticated C++
- Macro Facility,
- .R
- Information Technology Group, Austin, TX, Internal Original Issue January 1990.
- .IP [4]
- Mary Fontana, Martin Neath and Lamott Oren,
- .I
- Symbolic Computing for C++,
- .R
- Information Technology Group, Austin, TX, Internal Original Issue January 1990.
- .IP [5]
- Andrew Koenig and Bjarne Stroustrup,
- .I
- Exception Handling for C++,
- .R
- Submitted as document X3J16/90-042 to the ANSI C++ committee, July, 1990.
- .IP [6]
- Stanley Lippman,
- .I
- C++ Primer,
- .R
- Addison-Wesley, Reading, MA, 1989.
- .IP [7]
- Mike Miller,
- .I
- Exception Handling Without Language Extensions,
- .R
- Proceedings of the USENIX C++ Conference, Denver, CO, October 17-21, 1988,
- pp. 327-341.
- .IP [8]
- Texas Instruments Incorporated,
- .I
- COOL User's Guide,
- .R
- Information Technology Group, Austin, TX, Internal Original Issue January 1990.
-
-